package com.llbnk.springcoding.migrate;

import com.llbnk.springcoding.config.TestExcutor;
import com.llbnk.springcoding.pojo.RateDIffVo;
import com.llbnk.springcoding.util.ApolloUtils;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.internal.Diff;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;


@Slf4j
public abstract class AbsMigrateProcess<T> implements MigrateProcess<T> {

    public static final String MIGRATE_DATASOUCE_DIFF_MAP = "migrate_datasouce_diff_map";

    @Autowired
    private TestExcutor testExcutor;

    @Autowired
    private ApolloUtils apolloUtil;

    @Override
    public Object migrateSelect(String methodName, Object... data) {
        Map<String, RateDIffVo> rateMap =
                apolloUtil.getMap(MIGRATE_DATASOUCE_DIFF_MAP, RateDIffVo.class);
        RateDIffVo migrateSelect = rateMap.get("migrateSelect");
        int migrateFlag = migrateSelect.getFlag();
        switch (migrateFlag) {
            case 0:
                return selectOld(methodName, data);
            case 1:
                Object oldValue = selectOld(methodName, data);
                rateDiff(oldValue,methodName,"NEW",data,migrateSelect.getRate());
                return oldValue;
            case 2:
                Object newValue = selectNew(methodName, data);
                rateDiff(newValue,methodName,"OLD",data,migrateSelect.getRate());
                return newValue;
            case 3:
                return selectOld(methodName,data);
            default:
                return selectOld(methodName,data);

        }
    }

    private void rateDiff(Object needValue, String methodName, String type,Object[] data,double rate) {
        double newRate = (new Random().nextInt(100) + 1)/ 100.0;
        if(newRate > rate){
            log.info("this rate diff skip out,newRate:{},rate:{}",newRate,rate);
            return;
        }
        CompletableFuture.supplyAsync(() -> {
            Object diffValue = null;
            if("NEW".equals(type)){
                diffValue = selectNew(methodName,data);
            }else{
                diffValue = selectOld(methodName, data);
            }
            log.info("needValue:{},diffValue:{}",needValue,diffValue);
            if(!needValue.equals(diffValue)){
               log.error("rate diff error,needValue:{},methodName:{},data:{}",needValue,methodName,data);
            }
            return null;
        }, testExcutor.getTaskExecutor());
    }

    @Override
    public void migrateAdd(T data) {
        Map<String, RateDIffVo> rateMap =
                apolloUtil.getMap(MIGRATE_DATASOUCE_DIFF_MAP, RateDIffVo.class);
        RateDIffVo migrateSelect = rateMap.get("migrateSelect");
        int migrateFlag = migrateSelect.getFlag();
        switch (migrateFlag) {
            case 0:
                addOld(data);
                break;
            case 1:
                addOld(data);
                addNew(data);
                break;
            case 2:
                addNew(data);
                addOld(data);
                break;
            case 3:
                addNew(data);
                break;
            default:
                addOld(data);

        }
    }

    abstract Object selectOld(String methodName, Object... data);

    abstract Object selectNew(String methodName, Object... data);

    abstract void addOld(T data);

    abstract void addNew(T data);

}
